/*
 *  NFCSigning - Open source library for signing/validation of NDEF messages
 *  Copyright (C) 2009-2010 The NFCSigning Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */
package measure2;

import com.ericsson.nfc.signing.MessageToSign;
import com.ericsson.nfc.signing.MessageValidator;
import com.ericsson.nfc.signing.Signature;
import com.ericsson.nfc.signing.SignedMessage;
import com.ericsson.nfc.signing.algorithm.DSASigner;
import com.ericsson.nfc.signing.algorithm.ECDSASigner;
import com.ericsson.nfc.signing.algorithm.ImplementationDetector;
import com.ericsson.nfc.signing.algorithm.PrivateKey;
import com.ericsson.nfc.signing.algorithm.RSASSAPKCS1v15Signer;
import com.ericsson.nfc.signing.algorithm.RSASSAPSSSigner;
import com.ericsson.nfc.signing.algorithm.SignatureException;
import com.ericsson.nfc.signing.algorithm.Signer;
import com.ericsson.nfc.signing.certificate.Certificate;
import com.ericsson.nfc.signing.certificate.X509Certificate;
import com.ericsson.nfc.signing.record.CertificateBytes;
import com.ericsson.nfc.signing.record.CertificateField;
import com.ericsson.nfc.signing.record.URIRecord;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Date;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

//#if MyJSR257
//# import my.javax.microedition.contactless.ndef.NDEFMessage;
//# import my.javax.microedition.contactless.ndef.NDEFRecord;
//#else
import javax.microedition.contactless.ndef.NDEFMessage;
import javax.microedition.contactless.ndef.NDEFRecord;
import javax.microedition.contactless.ndef.NDEFRecordType;
//#endif

/**
 * @author emarkki
 */
public class MeasureSigningTimeMIDlet extends MIDlet implements CommandListener {

    private boolean midletPaused = false;
    
    private PrintStream out = System.out;
    
    Certificate[] trustedCerts;

    private Cert[] certs;

    private static final NDEFRecordType SMARTPOSTER =
            new NDEFRecordType(NDEFRecordType.NFC_FORUM_RTD, "urn:nfc:wkt:Sp");
    
    //<editor-fold defaultstate="collapsed" desc=" Generated Fields ">//GEN-BEGIN:|fields|0|
    private Form form;
    private ChoiceGroup choiceGroupRun;
    private TextField textFieldIterations;
    private ChoiceGroup choiceGroup;
    private Command exitCommand;
    private Command okCommand;
    private Command dumpFileCommand;
    //</editor-fold>//GEN-END:|fields|0|
    
    /**
     * The MeasureVerificationTimeMIDlet constructor.
     */
    public MeasureSigningTimeMIDlet() {
    }

    private void dumpFileCommandPerformed() {
        FileConnection conn = null;
        try {
            String fileName = System.getProperty("fileconn.dir.photos") + "verifytime.log";
            conn = (FileConnection) Connector.open(fileName, Connector.READ);
            if (!conn.exists()) {
                getDisplay().setCurrent(new Alert("No such file"));
                return;
            }
            
            InputStream in = conn.openDataInputStream();
            String s;
            int ch;
            while((ch = in.read()) != -1) {
                System.out.print((char)ch);
            }
            
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if(conn != null) {
                try {
                    conn.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    private void initMeasurements() {

        certs = new Cert[4];

        if (choiceGroupRun.isSelected(0)) {
        }
        if (choiceGroupRun.isSelected(1)) {
        }
        if (choiceGroupRun.isSelected(2)) {
            try {
                certs[0] = new Cert("Min User 2 (DSA) (2)", new PrivateKey(getClass().getResourceAsStream("files/minuser2-private.der")), Cert.KEY_DSA, new X509Certificate[]{new X509Certificate(getClass().getResourceAsStream("files/minuser2-signed.cer"))});
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        if (choiceGroupRun.isSelected(3)) {
            try {
                certs[1] = new Cert("Min User 3 (ECDSA) (2)", new PrivateKey(getClass().getResourceAsStream("files/minuser3-private.der")), Cert.KEY_ECDSA, new X509Certificate[]{new X509Certificate(getClass().getResourceAsStream("files/minuser3-signed.cer"))});
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        if (choiceGroupRun.isSelected(4)) {
            try {
                certs[2] = new Cert("Min User 1 (RSA) (2)", new PrivateKey(getClass().getResourceAsStream("files/minuser1-private.der")), Cert.KEY_RSA, new X509Certificate[]{new X509Certificate(getClass().getResourceAsStream("files/minuser1-signed.cer"))});
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        if (choiceGroupRun.isSelected(5)) {
            try {
                certs[3] = new Cert("Min User 1 (RSA) (2)", new PrivateKey(getClass().getResourceAsStream("files/minuser1-private.der")), Cert.KEY_RSA, new X509Certificate[]{new X509Certificate(getClass().getResourceAsStream("files/minuser1-signed.cer"))});
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
            

        try {
            trustedCerts = new Certificate[]{
                new X509Certificate(getClass().getResourceAsStream("files/NordicRootCA.cer")),
                new X509Certificate(getClass().getResourceAsStream("files/SwedenRootCA.cer")),
                new X509Certificate(getClass().getResourceAsStream("files/SwissRootCA.cer")),
                new X509Certificate(getClass().getResourceAsStream("files/ScandinaviaRootCA.cer"))
            };
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    

    //<editor-fold defaultstate="collapsed" desc=" Generated Methods ">//GEN-BEGIN:|methods|0|
    //</editor-fold>//GEN-END:|methods|0|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: initialize ">//GEN-BEGIN:|0-initialize|0|0-preInitialize
    /**
     * Initilizes the application.
     * It is called only once when the MIDlet is started. The method is called before the <code>startMIDlet</code> method.
     */
    private void initialize() {//GEN-END:|0-initialize|0|0-preInitialize
        // write pre-initialize user code here
//GEN-LINE:|0-initialize|1|0-postInitialize
        // write post-initialize user code here
    }//GEN-BEGIN:|0-initialize|2|
    //</editor-fold>//GEN-END:|0-initialize|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: startMIDlet ">//GEN-BEGIN:|3-startMIDlet|0|3-preAction
    /**
     * Performs an action assigned to the Mobile Device - MIDlet Started point.
     */
    public void startMIDlet() {//GEN-END:|3-startMIDlet|0|3-preAction
        // write pre-action user code here
        switchDisplayable(null, getForm());//GEN-LINE:|3-startMIDlet|1|3-postAction
        // write post-action user code here
    }//GEN-BEGIN:|3-startMIDlet|2|
    //</editor-fold>//GEN-END:|3-startMIDlet|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: resumeMIDlet ">//GEN-BEGIN:|4-resumeMIDlet|0|4-preAction
    /**
     * Performs an action assigned to the Mobile Device - MIDlet Resumed point.
     */
    public void resumeMIDlet() {//GEN-END:|4-resumeMIDlet|0|4-preAction
        // write pre-action user code here
//GEN-LINE:|4-resumeMIDlet|1|4-postAction
        // write post-action user code here
    }//GEN-BEGIN:|4-resumeMIDlet|2|
    //</editor-fold>//GEN-END:|4-resumeMIDlet|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: switchDisplayable ">//GEN-BEGIN:|5-switchDisplayable|0|5-preSwitch
    /**
     * Switches a current displayable in a display. The <code>display</code> instance is taken from <code>getDisplay</code> method. This method is used by all actions in the design for switching displayable.
     * @param alert the Alert which is temporarily set to the display; if <code>null</code>, then <code>nextDisplayable</code> is set immediately
     * @param nextDisplayable the Displayable to be set
     */
    public void switchDisplayable(Alert alert, Displayable nextDisplayable) {//GEN-END:|5-switchDisplayable|0|5-preSwitch
        // write pre-switch user code here
        Display display = getDisplay();//GEN-BEGIN:|5-switchDisplayable|1|5-postSwitch
        if (alert == null) {
            display.setCurrent(nextDisplayable);
        } else {
            display.setCurrent(alert, nextDisplayable);
        }//GEN-END:|5-switchDisplayable|1|5-postSwitch
        // write post-switch user code here
    }//GEN-BEGIN:|5-switchDisplayable|2|
    //</editor-fold>//GEN-END:|5-switchDisplayable|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Method: commandAction for Displayables ">//GEN-BEGIN:|7-commandAction|0|7-preCommandAction
    /**
     * Called by a system to indicated that a command has been invoked on a particular displayable.
     * @param command the Command that was invoked
     * @param displayable the Displayable where the command was invoked
     */
    public void commandAction(Command command, Displayable displayable) {//GEN-END:|7-commandAction|0|7-preCommandAction
 // write pre-action user code here
        if (displayable == form) {//GEN-BEGIN:|7-commandAction|1|38-preAction
            if (command == dumpFileCommand) {//GEN-END:|7-commandAction|1|38-preAction
 // write pre-action user code here
    dumpFileCommandPerformed();
//GEN-LINE:|7-commandAction|2|38-postAction
 // write post-action user code here
            } else if (command == exitCommand) {//GEN-LINE:|7-commandAction|3|16-preAction
 // write pre-action user code here
                exitMIDlet();//GEN-LINE:|7-commandAction|4|16-postAction
 // write post-action user code here
            } else if (command == okCommand) {//GEN-LINE:|7-commandAction|5|19-preAction
 // write pre-action user code here
//GEN-LINE:|7-commandAction|6|19-postAction
 // write post-action user code here
    startMeasurements();
            }//GEN-BEGIN:|7-commandAction|7|7-postCommandAction
        }//GEN-END:|7-commandAction|7|7-postCommandAction
 // write post-action user code here
    }//GEN-BEGIN:|7-commandAction|8|
    //</editor-fold>//GEN-END:|7-commandAction|8|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: form ">//GEN-BEGIN:|13-getter|0|13-preInit
    /**
     * Returns an initiliazed instance of form component.
     * @return the initialized component instance
     */
    public Form getForm() {
        if (form == null) {//GEN-END:|13-getter|0|13-preInit
 // write pre-init user code here
            form = new Form("Measure signing", new Item[] { getChoiceGroupRun(), getTextFieldIterations(), getChoiceGroup() });//GEN-BEGIN:|13-getter|1|13-postInit
            form.addCommand(getExitCommand());
            form.addCommand(getOkCommand());
            form.addCommand(getDumpFileCommand());
            form.setCommandListener(this);//GEN-END:|13-getter|1|13-postInit
 // write post-init user code here
        }//GEN-BEGIN:|13-getter|2|
        return form;
    }
    //</editor-fold>//GEN-END:|13-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: exitCommand ">//GEN-BEGIN:|15-getter|0|15-preInit
    /**
     * Returns an initiliazed instance of exitCommand component.
     * @return the initialized component instance
     */
    public Command getExitCommand() {
        if (exitCommand == null) {//GEN-END:|15-getter|0|15-preInit
 // write pre-init user code here
            exitCommand = new Command("Exit", Command.EXIT, 0);//GEN-LINE:|15-getter|1|15-postInit
 // write post-init user code here
        }//GEN-BEGIN:|15-getter|2|
        return exitCommand;
    }
    //</editor-fold>//GEN-END:|15-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: okCommand ">//GEN-BEGIN:|18-getter|0|18-preInit
    /**
     * Returns an initiliazed instance of okCommand component.
     * @return the initialized component instance
     */
    public Command getOkCommand() {
        if (okCommand == null) {//GEN-END:|18-getter|0|18-preInit
 // write pre-init user code here
            okCommand = new Command("Start", Command.OK, 0);//GEN-LINE:|18-getter|1|18-postInit
 // write post-init user code here
        }//GEN-BEGIN:|18-getter|2|
        return okCommand;
    }
    //</editor-fold>//GEN-END:|18-getter|2|

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: textFieldIterations ">//GEN-BEGIN:|20-getter|0|20-preInit
    /**
     * Returns an initiliazed instance of textFieldIterations component.
     * @return the initialized component instance
     */
    public TextField getTextFieldIterations() {
        if (textFieldIterations == null) {//GEN-END:|20-getter|0|20-preInit
 // write pre-init user code here
            textFieldIterations = new TextField("Iterations to run:", "1000", 32, TextField.NUMERIC);//GEN-LINE:|20-getter|1|20-postInit
 // write post-init user code here
        }//GEN-BEGIN:|20-getter|2|
        return textFieldIterations;
    }
    //</editor-fold>//GEN-END:|20-getter|2|

//<editor-fold defaultstate="collapsed" desc=" Generated Getter: choiceGroupRun ">//GEN-BEGIN:|21-getter|0|21-preInit
/**
 * Returns an initiliazed instance of choiceGroupRun component.
 * @return the initialized component instance
 */
public ChoiceGroup getChoiceGroupRun() {
    if (choiceGroupRun == null) {//GEN-END:|21-getter|0|21-preInit
 // write pre-init user code here
        choiceGroupRun = new ChoiceGroup("Run:", Choice.MULTIPLE);//GEN-BEGIN:|21-getter|1|21-postInit
        choiceGroupRun.append("Empty/null test", null);
        choiceGroupRun.append("Empty/null test (aggregated)", null);
        choiceGroupRun.append("Sign 1 - DSA", null);
        choiceGroupRun.append("Sign 2 - ECDSA", null);
        choiceGroupRun.append("Sign 3 - RSASSA-PSS", null);
        choiceGroupRun.append("Sign 4 - RSASSA-PKCS1", null);
        choiceGroupRun.setSelectedFlags(new boolean[] { true, true, true, true, true, true });
        choiceGroupRun.setFont(0, null);
        choiceGroupRun.setFont(1, null);
        choiceGroupRun.setFont(2, null);
        choiceGroupRun.setFont(3, null);
        choiceGroupRun.setFont(4, null);
        choiceGroupRun.setFont(5, null);//GEN-END:|21-getter|1|21-postInit
 // write post-init user code here
    }//GEN-BEGIN:|21-getter|2|
    return choiceGroupRun;
}
//</editor-fold>//GEN-END:|21-getter|2|

//<editor-fold defaultstate="collapsed" desc=" Generated Getter: choiceGroup ">//GEN-BEGIN:|29-getter|0|29-preInit
/**
 * Returns an initiliazed instance of choiceGroup component.
 * @return the initialized component instance
 */
public ChoiceGroup getChoiceGroup() {
    if (choiceGroup == null) {//GEN-END:|29-getter|0|29-preInit
 // write pre-init user code here
        choiceGroup = new ChoiceGroup("Output results:", Choice.EXCLUSIVE);//GEN-BEGIN:|29-getter|1|29-postInit
        choiceGroup.append("System.out", null);
        choiceGroup.append("Log-file: images/verifytime.log", null);
        choiceGroup.setSelectedFlags(new boolean[] { false, false });
        choiceGroup.setFont(0, null);
        choiceGroup.setFont(1, null);//GEN-END:|29-getter|1|29-postInit
 // write post-init user code here
    }//GEN-BEGIN:|29-getter|2|
    return choiceGroup;
}
//</editor-fold>//GEN-END:|29-getter|2|

//<editor-fold defaultstate="collapsed" desc=" Generated Getter: dumpFileCommand ">//GEN-BEGIN:|37-getter|0|37-preInit
/**
 * Returns an initiliazed instance of dumpFileCommand component.
 * @return the initialized component instance
 */
public Command getDumpFileCommand() {
    if (dumpFileCommand == null) {//GEN-END:|37-getter|0|37-preInit
 // write pre-init user code here
        dumpFileCommand = new Command("Dump file", Command.ITEM, 0);//GEN-LINE:|37-getter|1|37-postInit
 // write post-init user code here
    }//GEN-BEGIN:|37-getter|2|
    return dumpFileCommand;
}
//</editor-fold>//GEN-END:|37-getter|2|

    /**
     * Returns a display instance.
     * @return the display instance.
     */
    public Display getDisplay () {
        return Display.getDisplay(this);
    }

    /**
     * Exits MIDlet.
     */
    public void exitMIDlet() {
        switchDisplayable (null, null);
        destroyApp(true);
        notifyDestroyed();
    }

    /**
     * Called when MIDlet is started.
     * Checks whether the MIDlet have been already started and initialize/starts or resumes the MIDlet.
     */
    public void startApp() {
        if (midletPaused) {
            resumeMIDlet ();
        } else {
            initialize ();
            startMIDlet ();
        }
        midletPaused = false;
    }

    /**
     * Called when MIDlet is paused.
     */
    public void pauseApp() {
        midletPaused = true;
    }

    /**
     * Called to signal the MIDlet to terminate.
     * @param unconditional if true, then the MIDlet has to be unconditionally terminated and all resources has to be released.
     */
    public void destroyApp(boolean unconditional) {
    }

    private void startMeasurements() {
        
        FileConnection conn = null;
        
        try {
        
            if(choiceGroup.isSelected(1)) {
            
                String fileName = System.getProperty("fileconn.dir.photos")+"verifytime.log";
                System.out.println("Openning " + fileName);
                
                conn = (FileConnection) Connector.open(fileName, Connector.READ_WRITE);
                
//                if(!conn.exists()) {
//                    getDisplay().setCurrent(new Alert("no image folder"), getForm());
//                    return;
//                }
//                
//                StringBuffer sb = new StringBuffer();
//                for(Enumeration e = conn.list(); e.hasMoreElements();) {
//                    sb.append(e.nextElement());
//                    sb.append("\n");
//                }
//                getDisplay().setCurrent(new Alert("files:", sb.toString(), null, AlertType.INFO), getForm());
//                
//                conn.
//                
//                return;
                
                if(!conn.exists()) {
                    conn.create();
                } else {
                    conn.truncate(0);
                }
                out = new PrintStream(conn.openOutputStream());                
            }
        
        out.println();
        out.println();
        out.println(new Date());
        
        out.println("         \titeration\ttest\ttime");
        
        int numIterations = Integer.parseInt(textFieldIterations.getString());
        out.println("Iterations: " + numIterations);
        
        // Init data
        initMeasurements();
        
        
        
        runMeasurements(numIterations);
       
        out.println("DONE");
        out.flush();
        System.out.println("DONE");
        
        Alert finished = new Alert("Done", "Test finished", null, AlertType.INFO);
        finished.setTimeout(Alert.FOREVER);
        getDisplay().setCurrent(finished);
        
        } catch (IOException ex) {
            ex.printStackTrace();
            getDisplay().setCurrent(new Alert("IOException", ex.getMessage(), null, AlertType.ERROR), getForm());
        } catch (SecurityException ex) {
            ex.printStackTrace();
            getDisplay().setCurrent(new Alert("SecurityException", ex.getMessage(), null, AlertType.ERROR), getForm());
        } finally {
            
            if(out != System.out) {
                out.close();
            }
            
            if(conn != null) {
                try {
                    conn.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                    getDisplay().setCurrent(new Alert("IOException", ex.getMessage(), null, AlertType.ERROR), getForm());
                }
            }
        }
        
    }
    
    private void runMeasurements(int numIterations) {
        
        ImplementationDetector.getInstance().setUseSatsa(true);
        boolean satsaSupported = ImplementationDetector.getInstance().isSatsaAvailable();
        
        boolean useSatsa = satsaSupported;
        
        int printCounter = 0;
        
        for(int iteration = 0; iteration < numIterations; iteration++,printCounter++) {
           
            if(printCounter >= 10) {
                printCounter = 0;
                System.out.println(iteration);
            }
            
            boolean result = true;
            long time;
            
            // Run all tests
            for(int test = 0; test < choiceGroupRun.size(); test++) {

                if(!choiceGroupRun.isSelected(test)) {
                    continue;
                }
                
                long timeStart;
               
                
                // Run both with and without satsa if supported
                for(int s = 0; s < 2; s++) {
                
                    switch(test) {
                        case 0: {
                            timeStart = System.currentTimeMillis();
                            emptyMethod();
                            time = System.currentTimeMillis() - timeStart;
                            break;
                        }
                        case 1: {
                            timeStart = System.currentTimeMillis();
                            for(int i = 0; i < 1000000; i++) {
                                emptyMethod();
                            }
                            time = (System.currentTimeMillis() - timeStart);
                            break;
                        }
                        case 2: {
                            NDEFMessage signedMessage;
                            timeStart = System.currentTimeMillis();
                            signedMessage = sign(0);
                            time = System.currentTimeMillis() - timeStart;

                            result = verifyMessage(signedMessage, "http://www.ericsson.com", "C=SE,CN=Minimum User 2");
                            break;
                        }
                        case 3: {
                            NDEFMessage signedMessage;
                            timeStart = System.currentTimeMillis();
                            signedMessage = sign(1);
                            time = System.currentTimeMillis() - timeStart;

                            result = verifyMessage(signedMessage, "http://www.ericsson.com", "C=SE,CN=Minimum User 3");
                            break;
                        }
                        case 4: {
                            NDEFMessage signedMessage;
                            timeStart = System.currentTimeMillis();
                            signedMessage = sign(2);
                            time = System.currentTimeMillis() - timeStart;

                            result = verifyMessage(signedMessage, "http://www.ericsson.com", "C=SE,CN=Minimum User 1");
                            break;
                        }
                        case 5: {
                            NDEFMessage signedMessage;
                            timeStart = System.currentTimeMillis();
                            signedMessage = sign(3);
                            time = System.currentTimeMillis() - timeStart;

                            result = verifyMessage(signedMessage, "http://www.ericsson.com", "C=SE,CN=Minimum User 1");
                            break;
                        }
                        default: {
                            System.err.println("No such test");
                            return;
                        }
                    }

                    out.println("--Result:\t" + iteration + "\t" + test + "\t"+time + "\t" + useSatsa + "\t" + (!result ? "FAILED" : "OK") + (""));
                    
                    if(!satsaSupported) {
                        break;
                    }
                    useSatsa = !useSatsa;
                    ImplementationDetector.getInstance().setUseSatsa(useSatsa);
                    
                }
            }
            
            out.flush();
        }
    }
    
    public void emptyMethod() {}


    public NDEFMessage sign(int testIndex) {
        try {
            URIRecord uri1 = new URIRecord(new byte[]{(byte) 1}, "http://www.ericsson.com");
            NDEFMessage payload = new NDEFMessage(new NDEFRecord[]{uri1.toNDEFRecord()});
            Cert cert = certs[testIndex];
            PrivateKey privKey = cert.getPrivateKey();
            CertificateBytes[] chain = cert.getChainBytes();
            CertificateBytes[] storeChain;
            URIRecord chainURI;
            if (true) {
                storeChain = chain;
                chainURI = null;
            } /*else if(choiceGroupCertificateChain.isSelected(1)) {
            storeChain = new CertificateBytes[0];
            chainURI = new URIRecord(textFieldChainUri.getString());
            getWriterForm().append("Store the certificate chain for "+ cert.getTitle() +" on: " + chainURI.getURI() + "\n");
            } else {
            storeChain = new CertificateBytes[0];
            chainURI = cert.getBuiltInUri();
            }*/
            MessageToSign signMsg = new MessageToSign(payload);
            Signer signer;
            switch (testIndex) {
                case 0:
                    signer = new DSASigner(privKey, CertificateField.X509, storeChain, chainURI);
                    break;
                case 1:
                    signer = new ECDSASigner(privKey, CertificateField.X509, storeChain, chainURI);
                    break;
                case 2:
                    signer = new RSASSAPSSSigner(privKey, CertificateField.X509, storeChain, chainURI);
                    break;
                case 3:
                    signer = new RSASSAPKCS1v15Signer(privKey, CertificateField.X509, storeChain, chainURI);
                    break;
                default:
                    return null;
            }
            signMsg.setSigner(new int[]{0}, signer);
            SignedMessage signed = signMsg.signMessage();

            //Signature signature = signed.getRecordsSignature(0);
            //signatureBytes = signature.getBytes();

            NDEFMessage signedPayload = signed.toNDEFMessage();
            NDEFRecord smartPosterRecord = new NDEFRecord(SMARTPOSTER, new byte[0], signedPayload.toByteArray());

            //byte[] messageOnTag = smartPosterRecord.toByteArray();
            //Utils.dumpAsJavaByteArray(messageOnTag);

            return new NDEFMessage(new NDEFRecord[]{smartPosterRecord});
        } catch (SignatureException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    public boolean verifyMessage(NDEFMessage msg, String expectedUri, String expectedFrom) {
        
        if(msg == null) {
            return false;
        }

        NDEFRecord r = msg.getRecord(0);

        if (r == null) {
            return false;
        }

        NDEFMessage sp = r.getNestedNDEFMessage(0);

        int interestingIndex = 0;

        MessageValidator validatorInfo = new MessageValidator(trustedCerts, null, null);
        SignedMessage results = validatorInfo.validate(r.getNestedNDEFMessage(0), new int[]{interestingIndex});
        Signature signature = results.getRecordsSignature(interestingIndex);

        URIRecord uri = new URIRecord(sp.getRecords()[interestingIndex].getPayload(), 0);
        
        if(!expectedUri.equals(uri.getURI())) {
            return false;
        }

        if(signature == null) {
            return false;
        } else if(!signature.getStatus().isValid()) {
            return false;
        } else {
            if(signature.getStatus().getCertificateChain().getUserCertificate() instanceof X509Certificate) {
                String from = ((X509Certificate)signature.getStatus().getCertificateChain().getUserCertificate()).getStructure().getSubject().toString();

                return expectedFrom.equals(from);
            }
            return false;
        }
    }

}
